﻿///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2023, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Область ПрограммныйИнтерфейс

// Возвращает даты, которые отличаются от указанной даты ДатаОт на количество дней,
// входящих в указанный график ГрафикРаботы.
//
// Параметры:
//   ГрафикРаботы	- СправочникСсылка.Календари
//	             	- СправочникСсылка.ПроизводственныеКалендари - график или 
//                    производственный календарь, который необходимо использовать для расчета дат.
//   ДатаОт			- Дата - дата, от которой нужно рассчитать количество дней.
//   МассивДней		- Массив из Число - количество дней, на которые нужно увеличить дату начала.
//   РассчитыватьСледующуюДатуОтПредыдущей	- Булево - нужно ли рассчитывать следующую дату от предыдущей или
//											           все даты рассчитываются от переданной даты.
//   ВызыватьИсключение - Булево - если Истина, вызвать исключение в случае незаполненного графика.
//
// Возвращаемое значение:
//   Неопределено, Массив - массив дат, увеличенных на количество дней, входящих в график,
//	                        Если график ГрафикРаботы не заполнен, и ВызыватьИсключение = Ложь, возвращается Неопределено.
//
Функция ДатыПоКалендарю(Знач ГрафикРаботы, Знач ДатаОт, Знач МассивДней, Знач РассчитыватьСледующуюДатуОтПредыдущей = Ложь, ВызыватьИсключение = Истина) Экспорт
	
	Если Не ЗначениеЗаполнено(ГрафикРаботы) Тогда
		Если ВызыватьИсключение Тогда
			ВызватьИсключение НСтр("ru = 'Не указан график работы или производственный календарь.'");
		КонецЕсли;
		Возврат Неопределено;
	КонецЕсли;
	
	Если ТипЗнч(ГрафикРаботы) <> Тип("СправочникСсылка.ПроизводственныеКалендари") Тогда
		Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ГрафикиРаботы") Тогда
			МодульГрафикиРаботы = ОбщегоНазначения.ОбщийМодуль("ГрафикиРаботы");
			Возврат МодульГрафикиРаботы.ДатыПоГрафику(
				ГрафикРаботы, ДатаОт, МассивДней, РассчитыватьСледующуюДатуОтПредыдущей, ВызыватьИсключение);
		КонецЕсли;
	КонецЕсли;
	
	СдвигДней = ПриращениеДней(МассивДней, РассчитыватьСледующуюДатуОтПредыдущей);
	
	ВидыДнейВключаемыхВРасчет = Новый Массив();
	ВидыДнейВключаемыхВРасчет.Добавить(Перечисления.ВидыДнейПроизводственногоКалендаря.Рабочий); 
	ВидыДнейВключаемыхВРасчет.Добавить(Перечисления.ВидыДнейПроизводственногоКалендаря.Предпраздничный);
	
	Запрос = Новый Запрос();
	Запрос.УстановитьПараметр("ПроизводственныйКалендарь", ГрафикРаботы);
	Запрос.УстановитьПараметр("ДатаОт", НачалоДня(ДатаОт));
	Запрос.УстановитьПараметр("Дни", СдвигДней.ПриращениеДней.ВыгрузитьКолонку("КоличествоДней"));
	Запрос.УстановитьПараметр("ВидыДней", ВидыДнейВключаемыхВРасчет);
	Запрос.Текст =
		"ВЫБРАТЬ ПЕРВЫЕ 0
		|	КалендарныеГрафики.Дата КАК Дата
		|ИЗ
		|	РегистрСведений.ДанныеПроизводственногоКалендаря КАК КалендарныеГрафики
		|ГДЕ
		|	КалендарныеГрафики.Дата > &ДатаОт
		|	И КалендарныеГрафики.ПроизводственныйКалендарь = &ПроизводственныйКалендарь
		|	И КалендарныеГрафики.ВидДня В(&ВидыДней)
		|
		|УПОРЯДОЧИТЬ ПО
		|	Дата";

	// Ограничим выборку максимальной величиной сдвига для того, чтобы исключить избыточную выборку дней.
	СхемаЗапроса = Новый СхемаЗапроса();
	СхемаЗапроса.УстановитьТекстЗапроса(Запрос.Текст);
	СхемаЗапроса.ПакетЗапросов[0].Операторы[0].КоличествоПолучаемыхЗаписей = СдвигДней.Максимум;
	Запрос.Текст = СхемаЗапроса.ПолучитьТекстЗапроса();

	ЗапрошенныеДни = Новый Соответствие();
	Для Каждого СтрокаТаблицы Из СдвигДней.ПриращениеДней Цикл
		ЗапрошенныеДни.Вставить(СтрокаТаблицы.КоличествоДней, Ложь);
	КонецЦикла;
	
	Выборка = Запрос.Выполнить().Выбрать();
	Если Выборка.Количество() < СдвигДней.Максимум Тогда
		Если ВызыватьИсключение Тогда
			ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Производственный календарь ""%1"" не заполнен с даты %2 на указанное количество рабочих дней.'"), 
				ГрафикРаботы, 
				Формат(ДатаОт, "ДЛФ=D"));
		Иначе
			Возврат Неопределено;
		КонецЕсли;
	КонецЕсли;
	
	Дней = 0;
	Пока Выборка.Следующий() Цикл
		Дней = Дней + 1;
		Если ЗапрошенныеДни[Дней] = Ложь Тогда
			ЗапрошенныеДни.Вставить(Дней, Выборка.Дата);
		КонецЕсли;
	КонецЦикла;
	
	МассивДат = Новый Массив;
	Для Каждого СтрокаТаблицы Из СдвигДней.ПриращениеДней Цикл
		Дата = ЗапрошенныеДни[СтрокаТаблицы.КоличествоДней];
		ОбщегоНазначенияКлиентСервер.Проверить(ТипЗнч(Дата) = Тип("Дата") И ЗначениеЗаполнено(Дата));
		МассивДат.Добавить(Дата);
	КонецЦикла;
	
	Возврат МассивДат;
	
КонецФункции

// Возвращает дату, которая отличается указанной даты ДатаОт на количество дней,
// входящих в указанный график или производственный календарь ГрафикРаботы.
//
// Параметры:
//   ГрафикРаботы	- СправочникСсылка.Календари
//	             	- СправочникСсылка.ПроизводственныеКалендари - график или 
//                    производственный календарь, который необходимо использовать для расчета даты.
//   ДатаОт			- Дата - дата, от которой нужно рассчитать количество дней.
//   КоличествоДней	- Число - количество дней, на которые нужно увеличить дату начала.
//   ВызыватьИсключение - Булево - если Истина, вызвать исключение в случае незаполненного графика.
//
// Возвращаемое значение:
//   Дата, Неопределено - дата, увеличенная на количество дней, входящих в график.
//	                      Если выбранный график не заполнен, и ВызыватьИсключение = Ложь, возвращается Неопределено.
//
Функция ДатаПоКалендарю(Знач ГрафикРаботы, Знач ДатаОт, Знач КоличествоДней, ВызыватьИсключение = Истина) Экспорт
	
	Если Не ЗначениеЗаполнено(ГрафикРаботы) Тогда
		Если ВызыватьИсключение Тогда
			ВызватьИсключение НСтр("ru = 'Не указан график работы или производственный календарь.'");
		КонецЕсли;
		Возврат Неопределено;
	КонецЕсли;
	
	ДатаОт = НачалоДня(ДатаОт);
	
	Если КоличествоДней = 0 Тогда
		Возврат ДатаОт;
	КонецЕсли;
	
	МассивДней = Новый Массив;
	МассивДней.Добавить(КоличествоДней);
	
	МассивДат = ДатыПоКалендарю(ГрафикРаботы, ДатаОт, МассивДней, , ВызыватьИсключение);
	
	Возврат ?(МассивДат <> Неопределено, МассивДат[0], Неопределено);
	
КонецФункции

// Определяет количество дней, входящих в график, для указанного периода.
//
// Параметры:
//   ГрафикРаботы	- СправочникСсылка.Календари
//	             	- СправочникСсылка.ПроизводственныеКалендари - график или 
//                    производственный календарь, который необходимо использовать для расчета дней.
//   ДатаНачала		- Дата - дата начала периода.
//   ДатаОкончания	- Дата - дата окончания периода.
//   ВызыватьИсключение - Булево - если Истина, вызвать исключение в случае незаполненного графика.
//
// Возвращаемое значение:
//   Число		- количество дней между датами начала и окончания.
//	              Если график ГрафикРаботы не заполнен, и ВызыватьИсключение = Ложь, возвращается Неопределено.
//
Функция РазностьДатПоКалендарю(Знач ГрафикРаботы, Знач ДатаНачала, Знач ДатаОкончания, ВызыватьИсключение = Истина) Экспорт

	Если Не ЗначениеЗаполнено(ГрафикРаботы) Тогда
		Если ВызыватьИсключение Тогда
			ВызватьИсключение НСтр("ru = 'Не указан производственный календарь.'");
		КонецЕсли;
		Возврат Неопределено;
	КонецЕсли;

	Если ТипЗнч(ГрафикРаботы) <> Тип("СправочникСсылка.ПроизводственныеКалендари") Тогда
		Результат = Неопределено;
		Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ГрафикиРаботы") Тогда
			МодульГрафикиРаботы = ОбщегоНазначения.ОбщийМодуль("ГрафикиРаботы");
			Результат = МодульГрафикиРаботы.РазностьДатПоКалендарю(ГрафикРаботы, ДатаНачала, ДатаОкончания, ВызыватьИсключение);
		КонецЕсли;
		Возврат Результат;
	КонецЕсли;

	Если ДатаОкончания < ДатаНачала Тогда
		Врем = ДатаНачала;
		ДатаНачала = ДатаОкончания;
		ДатаОкончания = Врем;
	КонецЕсли;
	
	// Проверим, за все ли годы заполнен календарь, 
	// если есть хотя бы один год, в котором нет ни одного дня - не можем рассчитать.
	Годы = Новый Массив();
	Год = Год(ДатаНачала);
	Пока Год <= Год(ДатаОкончания) Цикл
		Годы.Добавить(Год);
		Год = Год + 1;
	КонецЦикла;
	
	Запрос = Новый Запрос();
	Запрос.УстановитьПараметр("Календарь", ГрафикРаботы);
	Запрос.УстановитьПараметр("Годы", Годы);
	Запрос.Текст = 
		"ВЫБРАТЬ РАЗЛИЧНЫЕ
		|	ДанныеКалендаря.Год КАК Год
		|ИЗ
		|	РегистрСведений.ДанныеПроизводственногоКалендаря КАК ДанныеКалендаря
		|ГДЕ
		|	ДанныеКалендаря.ПроизводственныйКалендарь = &Календарь
		|	И ДанныеКалендаря.Год В(&Годы)";
	Если Запрос.Выполнить().Выгрузить().Количество() <> Годы.Количество() Тогда
		Если ВызыватьИсключение Тогда
			СообщениеОбОшибке = НСтр("ru = 'График работы ""%1"" не заполнен на период %2.'");
			ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(СообщениеОбОшибке, ГрафикРаботы, ПредставлениеПериода(ДатаНачала, КонецДня(ДатаОкончания)));
		Иначе
			Возврат Неопределено;
		КонецЕсли;
	КонецЕсли;

	ВключаемыеВГрафик = Новый Массив();
	ВключаемыеВГрафик.Добавить(Перечисления.ВидыДнейПроизводственногоКалендаря.Рабочий);
	ВключаемыеВГрафик.Добавить(Перечисления.ВидыДнейПроизводственногоКалендаря.Предпраздничный);
	
	Запрос = Новый Запрос();
	Запрос.УстановитьПараметр("Календарь", ГрафикРаботы);
	Запрос.УстановитьПараметр("Годы", Годы);
	Запрос.УстановитьПараметр("ВидыДней", ВключаемыеВГрафик);
	Запрос.УстановитьПараметр("ДатаНачала", ДатаНачала);
	Запрос.УстановитьПараметр("ДатаОкончания", ДатаОкончания);
	Запрос.Текст = 
		"ВЫБРАТЬ
		|	КОЛИЧЕСТВО(ДанныеКалендаря.Дата) КАК Дней
		|ИЗ
		|	РегистрСведений.ДанныеПроизводственногоКалендаря КАК ДанныеКалендаря
		|ГДЕ
		|	ДанныеКалендаря.ПроизводственныйКалендарь = &Календарь
		|	И ДанныеКалендаря.Год В(&Годы)
		|	И ДанныеКалендаря.ВидДня В(&ВидыДней)
		|	И ДанныеКалендаря.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания";

	Возврат Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Дней")[0];

КонецФункции

// Конструктор параметров получения ближайших рабочих дат по календарю.
//  См. БлижайшиеРабочиеДаты.
//
// Параметры:
//  ПроизводственныйКалендарь	 - СправочникСсылка.ПроизводственныеКалендари	 -
//  	если указан, то НерабочиеПериоды будет по умолчанию заполнен как Массив из описаний,
//  	полученных методом ПериодыНерабочихДней.
// 
// Возвращаемое значение:
//  Структура:
//   * ПолучатьПредшествующие - Булево - способ получения ближайшей даты:
//       если Истина - определяются рабочие даты, предшествующие переданным в параметре НачальныеДаты,
//       если Ложь - получаются ближайшие рабочие даты, следующие за начальными датами.
//       Значение по умолчанию - Ложь:
//   * УчитыватьНерабочиеПериоды - Булево - определяет отношение к датам, выпадающим на периоды нерабочих дней календаря,
//       если Истина, даты, выпадающие на период нерабочих дней будут считаться нерабочими,
//       если Ложь, периоды нерабочих дней будут игнорироваться.
//       Значение по умолчанию - Истина:
//   * НерабочиеПериоды - Неопределено - уточняет периоды нерабочих дней, которые нужно учитывать,
//       можно установить Массив номеров периодов или описаний, полученных методом ПериодыНерабочихДней,
//       если Неопределено, будут учтены все периоды,
//       если заполнен параметр ПроизводственныйКалендарь, то все периоды этого календаря будут заполнены в НерабочиеПериоды.
//       Значение по умолчанию - Неопределено:
//   * ВызыватьИсключение - Булево - вызов исключения в случае не заполненного графика
//       если Истина, вызвать исключение, если график не заполнен.
//       если Ложь - даты, по которым не удалось определить ближайшую дату, будут просто пропущены.
//       Значение по умолчанию - Истина.
//
Функция ПараметрыПолученияБлижайшихРабочихДат(ПроизводственныйКалендарь = Неопределено) Экспорт
	Параметры = Новый Структура(
		"ПолучатьПредшествующие,
		|УчитыватьНерабочиеПериоды,
		|НерабочиеПериоды,
		|ВызыватьИсключение");
	Параметры.ПолучатьПредшествующие = Ложь;
	Параметры.УчитыватьНерабочиеПериоды = Истина;
	Параметры.ВызыватьИсключение = Истина;
	Если ПроизводственныйКалендарь <> Неопределено Тогда
		Параметры.НерабочиеПериоды = ПериодыНерабочихДней(ПроизводственныйКалендарь, Новый СтандартныйПериод());
	КонецЕсли;
	Возврат Параметры;
КонецФункции

// Определяет для каждой даты дату ближайшего к ней рабочего дня.
//
// Параметры:
//  ПроизводственныйКалендарь	 - СправочникСсылка.ПроизводственныеКалендари	 - календарь, используемый для расчета.
//  НачальныеДаты				 - Массив из Дата - даты, относительно которых будет выполнен поиск ближайших.
//  ПараметрыПолучения			 - см. ПараметрыПолученияБлижайшихРабочихДат.
// 
// Возвращаемое значение:
//  Соответствие из КлючИЗначение:
//   * Ключ - Дата - начальная дата,
//   * Значение - Дата - ближайшая к ней рабочая дата (если передана рабочая дата, то она же и возвращается).
//
Функция БлижайшиеРабочиеДаты(ПроизводственныйКалендарь, НачальныеДаты, ПараметрыПолучения = Неопределено) Экспорт
	
	Если ПараметрыПолучения = Неопределено Тогда
		ПараметрыПолучения = ПараметрыПолученияБлижайшихРабочихДат();
	КонецЕсли;
	
	ОбщегоНазначенияКлиентСервер.ПроверитьПараметр(
		"КалендарныеГрафики.БлижайшиеРабочиеДаты", 
		"ПроизводственныйКалендарь", 
		ПроизводственныйКалендарь, 
		Тип("СправочникСсылка.ПроизводственныеКалендари"));

	ОбщегоНазначенияКлиентСервер.Проверить(
		ЗначениеЗаполнено(ПроизводственныйКалендарь), 
		НСтр("ru = 'Не указан график или производственный календарь.'"), 
		"КалендарныеГрафики.БлижайшиеРабочиеДаты");
	
	ТекстыЗапросов = Новый Массив;
	Для Каждого НачальнаяДата Из НачальныеДаты Цикл
		Если Не ЗначениеЗаполнено(НачальнаяДата) Тогда
			Продолжить;
		КонецЕсли;
		ТекстЗапроса = 
			"ВЫБРАТЬ
			|	&НачальнаяДата КАК Дата
			|ПОМЕСТИТЬ ВТНачальныеДаты";
		ТекстЗапроса = СтрЗаменить(
			ТекстЗапроса, "&НачальнаяДата", СтрШаблон("ДАТАВРЕМЯ(%1)", Формат(НачальнаяДата, "ДФ=гггг,ММ,дд"))); // АПК:456 Не требует локализации
		Если ТекстыЗапросов.Количество() > 0 Тогда
			ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ПОМЕСТИТЬ ВТНачальныеДаты", "");
		КонецЕсли;
		ТекстыЗапросов.Добавить(ТекстЗапроса);
	КонецЦикла;

	ТекстЗапроса = СтрСоединить(ТекстыЗапросов, Символы.ПС + "ОБЪЕДИНИТЬ ВСЕ" + Символы.ПС);

	Если ПустаяСтрока(ТекстЗапроса) Тогда
		Возврат Новый Соответствие;
	КонецЕсли;

	Запрос = Новый Запрос(ТекстЗапроса);
	Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
	Запрос.Выполнить();
	
	ТекстЗапроса = 
		"ВЫБРАТЬ
		|	НачальныеДаты.Дата,
		|	МИНИМУМ(ДатыКалендаря.Дата) КАК БлижайшаяДата
		|ИЗ
		|	ВТНачальныеДаты КАК НачальныеДаты
		|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДанныеПроизводственногоКалендаря КАК ДатыКалендаря
		|		ПО ДатыКалендаря.Дата >= НачальныеДаты.Дата
		|		И ДатыКалендаря.ПроизводственныйКалендарь = &ПроизводственныйКалендарь
		|		И ДатыКалендаря.ВидДня В (ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Рабочий),
		|			ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Предпраздничный))
		|		И ДатыКалендаря.Дата НЕ В (&НерабочиеДаты)
		|СГРУППИРОВАТЬ ПО
		|	НачальныеДаты.Дата";
	
	Если ПараметрыПолучения.ПолучатьПредшествующие Тогда
		ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "МИНИМУМ(ДатыКалендаря.Дата)", "МАКСИМУМ(ДатыКалендаря.Дата)");
		ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ДатыКалендаря.Дата >= НачальныеДаты.Дата", "ДатыКалендаря.Дата <= НачальныеДаты.Дата");
	КонецЕсли;
	Запрос.Текст = ТекстЗапроса;
	Запрос.УстановитьПараметр("ПроизводственныйКалендарь", ПроизводственныйКалендарь);
	
	НерабочиеДаты = Новый Массив;
	Если ПараметрыПолучения.УчитыватьНерабочиеПериоды Тогда
		НерабочиеДаты = НерабочиеДатыПоНерабочимПериодам(ПараметрыПолучения.НерабочиеПериоды, ПроизводственныйКалендарь);
	КонецЕсли;
	Запрос.УстановитьПараметр("НерабочиеДаты", НерабочиеДаты);
	
	Выборка = Запрос.Выполнить().Выбрать();
	
	ДатыРабочихДней = Новый Соответствие;
	Пока Выборка.Следующий() Цикл
		Если ЗначениеЗаполнено(Выборка.БлижайшаяДата) Тогда
			ДатыРабочихДней.Вставить(Выборка.Дата, Выборка.БлижайшаяДата);
		Иначе 
			Если ПараметрыПолучения.ВызыватьИсключение Тогда
				ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Невозможно определить ближайшую рабочую дату для даты %1, 
						 |возможно, производственный календарь не заполнен.'"), 
					Формат(Выборка.Дата, "ДЛФ=D"));
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
	Возврат ДатыРабочихДней;
	
КонецФункции

// Составляет расписания работы для дат, включенных в указанные графики на указанный период.
// Если расписание на предпраздничный день не задано, то оно определяется так, как если бы этот день был бы рабочим.
// Необходимо учитывать, что для работы этой функции обязательно наличие подсистемы ГрафикиРаботы.
//
// Параметры:
//  Графики       - Массив - массив элементов типа СправочникСсылка.Календари, для которых составляются расписания.
//  ДатаНачала    - Дата   - дата начала периода, за который нужно составить расписания.
//  ДатаОкончания - Дата   - дата окончания периода.
//
// Возвращаемое значение:
//   ТаблицаЗначений:
//    * ГрафикРаботы    - СправочникСсылка.Календари - график работы.
//    * ДатаГрафика     - Дата - дата в графике работы ГрафикРаботы.
//    * ВремяНачала     - Дата - время начала работы в день ДатаГрафика.
//    * ВремяОкончания  - Дата - время окончания работы в день ДатаГрафика.
//
Функция РасписанияРаботыНаПериод(Графики, ДатаНачала, ДатаОкончания) Экспорт
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ГрафикиРаботы") Тогда
		МодульГрафикиРаботы = ОбщегоНазначения.ОбщийМодуль("ГрафикиРаботы");
		Возврат МодульГрафикиРаботы.РасписанияРаботыНаПериод(Графики, ДатаНачала, ДатаОкончания);
	КонецЕсли;
	
	ВызватьИсключение НСтр("ru = 'Подсистема ""Графики работы"" не обнаружена.'");
	
КонецФункции

// Создает в менеджере временную таблицу ВТРасписанияРаботы с колонками, соответствующими возвращаемому значению
// функции РасписанияРаботыНаПериод.
// Необходимо учитывать, что для работы этой функции обязательно наличие подсистемы ГрафикиРаботы.
//
// Параметры:
//  МенеджерВременныхТаблиц - МенеджерВременныхТаблиц - менеджер, в котором будет создана временная таблица.
//  Графики       - Массив - массив элементов типа СправочникСсылка.Календари, для которых составляются расписания.
//  ДатаНачала    - Дата   - дата начала периода, за который нужно составить расписания.
//  ДатаОкончания - Дата   - дата окончания периода.
//
Процедура СоздатьВТРасписанияРаботыНаПериод(МенеджерВременныхТаблиц, Графики, ДатаНачала, ДатаОкончания) Экспорт
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ГрафикиРаботы") Тогда
		МодульГрафикиРаботы = ОбщегоНазначения.ОбщийМодуль("ГрафикиРаботы");
		МодульГрафикиРаботы.СоздатьВТРасписанияРаботыНаПериод(МенеджерВременныхТаблиц, Графики, ДатаНачала, ДатаОкончания);
		Возврат;
	КонецЕсли;
	
	ВызватьИсключение НСтр("ru = 'Подсистема ""Графики работы"" не обнаружена.'");
	
КонецПроцедуры

// Заполняет реквизит в форме, в том случае, если используется единственный производственный календарь.
//
// Параметры:
//  Форма         - ФормаКлиентскогоПриложения - форма, в которой требуется заполнить реквизит.
//  ПутьРеквизита - Строка           - путь к данным, например: "Объект.ПроизводственныйКалендарь".
//  КПП			  - Строка           - индивидуальный номер налогоплательщика (код причины постановки на учет) для определения региона.
//
Процедура ЗаполнитьПроизводственныйКалендарьВФорме(Форма, ПутьРеквизита, КПП = Неопределено) Экспорт
	
	Календарь = Неопределено;
	
	Если Не ПолучитьФункциональнуюОпцию("ИспользоватьНесколькоПроизводственныхКалендарей") Тогда
		Календарь = ЕдинственныйПроизводственныйКалендарь();
	Иначе
		Календарь = РегиональныйПроизводственныйКалендарь(КПП);
	КонецЕсли;
	
	Если Календарь <> Неопределено Тогда
		ОбщегоНазначенияКлиентСервер.УстановитьРеквизитФормыПоПути(Форма, ПутьРеквизита, Календарь);
	КонецЕсли;
	
КонецПроцедуры

// Возвращает основной производственный календарь, используемый в учете.
//
// Возвращаемое значение:
//   СправочникСсылка.ПроизводственныеКалендари, Неопределено - основной производственный календарь или 
//                                                              Неопределено, в случае если он не обнаружен.
//
Функция ОсновнойПроизводственныйКалендарь() Экспорт
		
	Если Метаданные.Обработки.Найти("ЗаполнениеКалендарныхГрафиков") = Неопределено Тогда
		Возврат Неопределено;
	КонецЕсли;	
	
	МодульЗаполнениеКалендарныхГрафиков = ОбщегоНазначения.ОбщийМодуль("Обработки.ЗаполнениеКалендарныхГрафиков");
	Возврат МодульЗаполнениеКалендарныхГрафиков.ОсновнойПроизводственныйКалендарь();
	
КонецФункции

// Готовит описание особых нерабочих периодов, установленных, например, законодательно.
// Такие периоды могут учитываться графиками, переопределяя заполнение по данным производственного календаря.
// 
// Параметры:
//   ПроизводственныйКалендарь - СправочникСсылка.ПроизводственныеКалендари - календарь, который является источником.
//   ПериодОтбор - СтандартныйПериод - временной интервал, в пределах которого нужно определить нерабочие периоды.
// Возвращаемое значение:
//   Массив - массив элементов типа Структура с полями:
//    * Номер     - Число - порядковый номер периода, может использоваться для идентификации.
//    * Период    - СтандартныйПериод - нерабочий период.
//    * Основание - Строка - нормативный акт, на основании которого установлен нерабочий период.
//    * Даты - Массив из Дата - даты, входящие в нерабочий период.
//    * Представление  - Строка - пользовательское представление периода.
//
Функция ПериодыНерабочихДней(ПроизводственныйКалендарь, ПериодОтбор) Экспорт

	Периоды = Новый Массив;
	Если Метаданные.Обработки.Найти("ЗаполнениеКалендарныхГрафиков") = Неопределено Тогда
		Возврат Периоды;
	КонецЕсли;
	
	МодульЗаполнениеКалендарныхГрафиков = ОбщегоНазначения.ОбщийМодуль("Обработки.ЗаполнениеКалендарныхГрафиков");
	Периоды = МодульЗаполнениеКалендарныхГрафиков.ПериодыНерабочихДней(ПроизводственныйКалендарь, ПериодОтбор);
	
	УдалитьПериодыНеСоответствующиеОтбору(Периоды, ПериодОтбор);
	
	Возврат Периоды;

КонецФункции

#Область ДляВызоваИзДругихПодсистем

// ИнтернетПоддержкаПользователей.РаботаСКлассификаторами

// Событие возникает при сборе информации о классификаторах, регистрируем производственные календари.
// 
// Параметры:
//   Классификаторы - см. РаботаСКлассификаторамиПереопределяемый.ПриДобавленииКлассификаторов.Классификаторы
//
Процедура ПриДобавленииКлассификаторов(Классификаторы) Экспорт
	
	Описание = Неопределено;
	Если ОбщегоНазначения.ПодсистемаСуществует("ИнтернетПоддержкаПользователей.РаботаСКлассификаторами") Тогда
		МодульРаботаСКлассификаторами = ОбщегоНазначения.ОбщийМодуль("РаботаСКлассификаторами");
		Описание = МодульРаботаСКлассификаторами.ОписаниеКлассификатора();
	КонецЕсли;
	Если Описание = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	Описание.Идентификатор = ИдентификаторКлассификатора();
	Описание.Наименование = НСтр("ru = 'Календари'");
	Описание.ОбновлятьАвтоматически = Истина;
	Описание.ОбщиеДанные = Истина;
	Описание.ОбработкаРазделенныхДанных = Истина;
	Описание.СохранятьФайлВКэш = Истина;
	
	Классификаторы.Добавить(Описание);
	
КонецПроцедуры

// См. РаботаСКлассификаторамиПереопределяемый.ПриЗагрузкеКлассификатора.
Процедура ПриЗагрузкеКлассификатора(Идентификатор, Версия, Адрес, Обработан, ДополнительныеПараметры) Экспорт
	
	Если Идентификатор <> ИдентификаторКлассификатора() Тогда
		Возврат;
	КонецЕсли;
	
	ЗагрузитьДанныеПроизводственныхКалендарей(Версия, Адрес, Обработан, ДополнительныеПараметры);
	
КонецПроцедуры

// Конец ИнтернетПоддержкаПользователей.РаботаСКлассификаторами

#КонецОбласти

#Область УстаревшиеПроцедурыИФункции

// Устарела. Следует использовать: 
// - КалендарныеГрафики.БлижайшиеРабочиеДаты - для производственного календаря, 
// - или ГрафикиРаботы.БлижайшиеДатыВключенныеВГрафик - для графика работы.
// Определяет для каждой даты дату ближайшего к ней рабочего дня.
//
// Параметры:
//    График	- СправочникСсылка.Календари
//	        	- СправочникСсылка.ПроизводственныеКалендари - график или 
//                    производственный календарь, который необходимо использовать для расчета.
//    НачальныеДаты 				- Массив - массив дат (Дата).
//    ПолучатьПредшествующие		- Булево - способ получения ближайшей даты:
//										если Истина - определяются рабочие даты, предшествующие переданным в параметре НачальныеДаты, 
//										если Ложь - получаются даты не ранее начальной даты.
//    ВызыватьИсключение - Булево - если Истина, вызвать исключение в случае незаполненного графика.
//    ИгнорироватьНезаполненностьГрафика - Булево - если Истина, то в любом случае будет возвращено соответствие. 
//										Начальные даты, для которых не будет значений из-за незаполненности графика, включены не будут.
//
// Возвращаемое значение:
//    - Соответствие из КлючИЗначение:
//      * Ключ - Дата - дата из переданного массива
//      * Значение - Дата - ближайшая к ней рабочая дата (если передана рабочая дата, то она же и возвращается).
//							Если выбранный график не заполнен, и ВызыватьИсключение = Ложь, возвращается Неопределено
//    - Неопределено
//
Функция ДатыБлижайшихРабочихДней(График, НачальныеДаты, ПолучатьПредшествующие = Ложь, ВызыватьИсключение = Истина, 
	ИгнорироватьНезаполненностьГрафика = Ложь) Экспорт
	
	Если ТипЗнч(График) <> Тип("СправочникСсылка.ПроизводственныеКалендари") Тогда
		Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ГрафикиРаботы") Тогда
			МодульГрафикиРаботы = ОбщегоНазначения.ОбщийМодуль("ГрафикиРаботы");
			ПараметрыПолучения = МодульГрафикиРаботы.ПараметрыПолученияБлижайшихДатПоГрафику();
			ПараметрыПолучения.ПолучатьПредшествующие = ПолучатьПредшествующие;
			ПараметрыПолучения.ВызыватьИсключение = ВызыватьИсключение;
			ПараметрыПолучения.ИгнорироватьНезаполненностьГрафика = ИгнорироватьНезаполненностьГрафика;
			Возврат МодульГрафикиРаботы.БлижайшиеДатыВключенныеВГрафик(График, НачальныеДаты, ПараметрыПолучения);
		КонецЕсли;
	КонецЕсли;
	
	ПараметрыПолучения = ПараметрыПолученияБлижайшихРабочихДат();
	ПараметрыПолучения.ПолучатьПредшествующие = ПолучатьПредшествующие;
	ПараметрыПолучения.ВызыватьИсключение = ВызыватьИсключение;
	Возврат БлижайшиеРабочиеДаты(График, НачальныеДаты, ПараметрыПолучения);
	
КонецФункции

#КонецОбласти

#КонецОбласти

#Область СлужебныйПрограммныйИнтерфейс

// Создает таблицу ПриращениеДней, в которой для каждого элемента из МассивДней 
// формируется строка с индексом элемента и значением - количеством дней.
// Рассчитывает максимальный сдвиг дней.
// 
// Параметры:
//  МассивДней - Массив из Число - массив дней
//  РассчитыватьСледующуюДатуОтПредыдущей - Булево - рассчитывать следующую дату от предыдущей
// 
// Возвращаемое значение:
//  Структура:
//   * ПриращениеДней - ТаблицаЗначений
//   * Максимум - Число
//
Функция ПриращениеДней(МассивДней, Знач РассчитыватьСледующуюДатуОтПредыдущей = Ложь) Экспорт

	Результат = Новый Структура();
	Результат.Вставить("ПриращениеДней", Новый ТаблицаЗначений);
	Результат.Вставить("Максимум", 0);

	Результат.ПриращениеДней.Колонки.Добавить("ИндексСтроки", Новый ОписаниеТипов("Число"));
	Результат.ПриращениеДней.Колонки.Добавить("КоличествоДней", Новый ОписаниеТипов("Число"));
	
	КоличествоДней = 0;
	НомерСтроки = 0;
	Для Каждого СтрокаДней Из МассивДней Цикл
		КоличествоДней = КоличествоДней + СтрокаДней;
		Строка = Результат.ПриращениеДней.Добавить();
		Строка.ИндексСтроки = НомерСтроки;
		Строка.КоличествоДней = ?(РассчитыватьСледующуюДатуОтПредыдущей, КоличествоДней, СтрокаДней);
		Результат.Максимум = Макс(Результат.Максимум, Строка.КоличествоДней);
		НомерСтроки = НомерСтроки + 1;
	КонецЦикла;
	
	Возврат Результат;

КонецФункции

// Предназначена для обновления связанных с производственным календарем элементов, 
// например, Графиков работы.
//
// Параметры:
//  ТаблицаИзменений - ТаблицаЗначений:
//    * КодПроизводственногоКалендаря - Число - код производственного календаря, данные которого изменились,
//    * Год - Число - год, за который нужно обновить данные.
//
Процедура РаспространитьИзмененияДанныхПроизводственныхКалендарей(ТаблицаИзменений) Экспорт
	
	КалендарныеГрафикиПереопределяемый.ПриОбновленииПроизводственныхКалендарей(ТаблицаИзменений);
	
	Если ОбщегоНазначения.РазделениеВключено() Тогда
		ЗапланироватьОбновлениеДанныхЗависимыхОтПроизводственныхКалендарей(ТаблицаИзменений);
		Возврат;
	КонецЕсли;
	
	ЗаполнитьДанныеЗависимыеОтПроизводственныхКалендарей(ТаблицаИзменений);
	
КонецПроцедуры

// Предназначена для обновления в областях данных связанных с производственным календарем элементов, 
// например, Графиков работы.
//
// Параметры:
//  ТаблицаИзменений - ТаблицаЗначений:
//    * КодПроизводственногоКалендаря - Число - код производственного календаря, данные которого изменились,
//    * Год - Число - год, за который нужно обновить данные.
//
Процедура ЗаполнитьДанныеЗависимыеОтПроизводственныхКалендарей(ТаблицаИзменений) Экспорт
	
	Если ТаблицаИзменений.Количество() = 0 Тогда
		Возврат;
	КонецЕсли;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ГрафикиРаботы") Тогда
		МодульГрафикиРаботы = ОбщегоНазначения.ОбщийМодуль("ГрафикиРаботы");
		МодульГрафикиРаботы.ОбновитьГрафикиРаботыПоДаннымПроизводственныхКалендарей(ТаблицаИзменений);
	КонецЕсли;
	
	КалендарныеГрафикиПереопределяемый.ПриОбновленииДанныхЗависимыхОтПроизводственныхКалендарей(ТаблицаИзменений);
	
КонецПроцедуры

// Определяет внутренний идентификатор классификатора для подсистемы РаботаСКлассификаторами.
//
// Возвращаемое значение:
//  Строка - идентификатор классификатора.
//
Функция ИдентификаторКлассификатора() Экспорт
	Возврат "Calendars20";
КонецФункции

// Определяет версию данных календарей, встроенных в конфигурацию.
//
// Возвращаемое значение:
//   Число - номер версии.
//
Функция ВерсияКалендарей() Экспорт
	
	Если Метаданные.Обработки.Найти("ЗаполнениеКалендарныхГрафиков") = Неопределено Тогда
		Возврат 0;
	КонецЕсли;
	
	МодульЗаполнениеКалендарныхГрафиков = ОбщегоНазначения.ОбщийМодуль("Обработки.ЗаполнениеКалендарныхГрафиков");
	Возврат МодульЗаполнениеКалендарныхГрафиков.ВерсияКалендарей();
	
КонецФункции

// Определяет версию загруженных в ИБ данных классификатора.
//
// Возвращаемое значение:
//   Число - номер версии загруженных данных, 0 - если подсистема работы с классификаторами не существует.
//
Функция ВерсияЗагруженныхКалендарей() Экспорт
	
	ВерсияЗагруженныхКалендарей = Неопределено;
	Если ОбщегоНазначения.ПодсистемаСуществует("ИнтернетПоддержкаПользователей.РаботаСКлассификаторами") Тогда
		МодульРаботаСКлассификаторами = ОбщегоНазначения.ОбщийМодуль("РаботаСКлассификаторами");
		ВерсияЗагруженныхКалендарей = МодульРаботаСКлассификаторами.ВерсияКлассификатора(ИдентификаторКлассификатора());
	КонецЕсли;
	
	Если ВерсияЗагруженныхКалендарей = Неопределено Тогда
		ВерсияЗагруженныхКалендарей = 0;
	КонецЕсли;
	
	Возврат ВерсияЗагруженныхКалендарей;
	
КонецФункции

// Запрашивает файл с данными классификатора календарей. 
// Преобразует полученный файл в структуру с таблицами календарей и их данных.
// Если подсистема РаботаСКлассификаторами отсутствует или не удалось получить файл классификатора, вызывается исключение.
//
// Возвращаемое значение:
//  Структура:
//   * ПроизводственныеКалендари - Структура:
//     * ИмяТаблицы - Строка          - имя таблицы.
//     * Данные     - ТаблицаЗначений - преобразованная из XML таблица календарей.
//   * ДанныеПроизводственныхКалендарей - Структура:
//     * ИмяТаблицы - Строка          - имя таблицы.
//     * Данные     - ТаблицаЗначений - преобразованная из XML таблица данных календарей.
//
Функция ДанныеКлассификатора() Экспорт
	
	ДанныеФайлов = Неопределено;
	
	Идентификаторы = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(ИдентификаторКлассификатора());
	Если ОбщегоНазначения.ПодсистемаСуществует("ИнтернетПоддержкаПользователей.РаботаСКлассификаторами") Тогда
		МодульРаботаСКлассификаторами = ОбщегоНазначения.ОбщийМодуль("РаботаСКлассификаторами");
		ДанныеФайлов = МодульРаботаСКлассификаторами.ПолучитьФайлыКлассификаторов(Идентификаторы);
	КонецЕсли;
	
	Если ДанныеФайлов = Неопределено Тогда
		ТекстСообщения = НСтр("ru = 'Не удалось получить данные календаря.
                               |Классификаторы не поддерживаются или подсистема ""Работа с классификаторами"" отсутствует.'");
		ВызватьИсключение ТекстСообщения;
	КонецЕсли;
	
	Если Не ПустаяСтрока(ДанныеФайлов.КодОшибки) Тогда
		ИмяСобытия = НСтр("ru = 'Календарные графики.Получение файла классификатора'", ОбщегоНазначения.КодОсновногоЯзыка());
		ЗаписьЖурналаРегистрации(
			ИмяСобытия, 
			УровеньЖурналаРегистрации.Ошибка,,, 
			СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Не удалось получить данные календаря. 
                      |%1'"), 
				ДанныеФайлов.ИнформацияОбОшибке));
		ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не удалось получить данные календаря.
                               |%1.'"), 
			ДанныеФайлов.СообщениеОбОшибке);
		ВызватьИсключение ТекстСообщения;
	КонецЕсли;
	
	ОтборСтрок = Новый Структура("Идентификатор");
	ОтборСтрок.Идентификатор = ИдентификаторКлассификатора();
	НайденныеСтроки = ДанныеФайлов.ДанныеКлассификаторов.НайтиСтроки(ОтборСтрок);
	Если НайденныеСтроки.Количество() = 0 Тогда
		ТекстСообщения = НСтр("ru = 'Не удалось получить данные календаря.
                               |Полученные классификаторы не содержат календарей.'");
		ВызватьИсключение ТекстСообщения;
	КонецЕсли;
	
	СведенияФайла = НайденныеСтроки[0];
	
	Если СведенияФайла.Версия < ВерсияКалендарей() Тогда
		ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не удалось обработать полученные данные календаря из-за конфликта версий.
                  |Версия календарей
                  |- полученного классификатора %1, 
                  |- встроенных в конфигурацию %2, 
                  |- загруженного ранее классификатора %3.
                  |Рекомендуется выполнить обновление классификаторов.'"),
			СведенияФайла.Версия,
			ВерсияКалендарей(),
			ВерсияЗагруженныхКалендарей());
		ВызватьИсключение ТекстСообщения;
	КонецЕсли;
	
	Попытка
		ДанныеКлассификатора = ДанныеФайлаКлассификатора(СведенияФайла.АдресФайла);
	Исключение
		ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не удалось обработать полученные данные календаря.
                  |%1.'"),
			ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
		ВызватьИсключение ТекстСообщения;
	КонецПопытки;
	
	Возврат ДанныеКлассификатора;
	
КонецФункции

////////////////////////////////////////////////////////////////////////////////
// Обработчики событий подсистем конфигурации.

// См. ОбновлениеИнформационнойБазыБСП.ПриДобавленииОбработчиковОбновления.
Процедура ПриДобавленииОбработчиковОбновления(Обработчики) Экспорт
	
	Обработчик = Обработчики.Добавить();
	Обработчик.НачальноеЗаполнение = Истина;
	Обработчик.Процедура = "КалендарныеГрафики.ОбновитьПроизводственныеКалендари";
	Обработчик.ОбщиеДанные = Истина;
	
	Обработчик = Обработчики.Добавить();
	Обработчик.Версия = "3.0.1.66";
	Обработчик.Процедура = "КалендарныеГрафики.ОбновитьДанныеЗависимыхПроизводственныхКалендарей";
	Обработчик.РежимВыполнения = "Оперативно";
	Обработчик.ОбщиеДанные = Истина;
	
	Обработчик = Обработчики.Добавить();
	Обработчик.Версия = "3.0.1.102";
	Обработчик.Процедура = "КалендарныеГрафики.ОбновитьИспользованиеНесколькихПроизводственныхКалендарей";
	Обработчик.РежимВыполнения = "Оперативно";
	Обработчик.ОбщиеДанные = Истина;
	
	Обработчик = Обработчики.Добавить();
	Обработчик.Версия = "3.1.3.113";
	Обработчик.Процедура = "КалендарныеГрафики.СброситьВерсиюКлассификатора";
	Обработчик.РежимВыполнения = "Оперативно";
	Обработчик.ОбщиеДанные = Истина;
	
	Обработчик = Обработчики.Добавить();
	Обработчик.Версия = "3.1.5.80";
	Обработчик.Процедура = "КалендарныеГрафики.ИсправитьДанныеЗависимыхКалендарей";
	Обработчик.РежимВыполнения = "Оперативно";
	Обработчик.ОбщиеДанные = Истина;
	
	Обработчик = Обработчики.Добавить();
	Обработчик.Версия = ВерсияОбновленияПроизводственныхКалендарей();
	Обработчик.Процедура = "КалендарныеГрафики.ОбновитьПроизводственныеКалендари";
	Обработчик.РежимВыполнения = "Оперативно";
	Обработчик.ОбщиеДанные = Истина;
	
	Обработчик = Обработчики.Добавить();
	Обработчик.Версия = ВерсияОбновленияДанныхПроизводственныхКалендарей();
	Обработчик.Процедура = "КалендарныеГрафики.ОбновитьДанныеПроизводственныхКалендарей";
	Обработчик.РежимВыполнения = "Оперативно";
	Обработчик.ОбщиеДанные = Истина;
	
	ДобавитьОбработчикДанныхЗависимыхОтПроизводственныхКалендарей(Обработчики);
	
КонецПроцедуры

// См. ПользователиПереопределяемый.ПриОпределенииНазначенияРолей
Процедура ПриОпределенииНазначенияРолей(НазначениеРолей) Экспорт
	
	// ТолькоДляПользователейСистемы.
	НазначениеРолей.ТолькоДляПользователейСистемы.Добавить(
		Метаданные.Роли.ДобавлениеИзменениеКалендарныхГрафиков.Имя);
	
КонецПроцедуры

// Параметры:
//   Типы - см. ВыгрузкаЗагрузкаДанныхПереопределяемый.ПриЗаполненииТиповОбщихДанныхПоддерживающихСопоставлениеСсылокПриЗагрузке.Типы
//
Процедура ПриЗаполненииТиповОбщихДанныхПоддерживающихСопоставлениеСсылокПриЗагрузке(Типы) Экспорт
	
	Типы.Добавить(Метаданные.Справочники.ПроизводственныеКалендари);
	
КонецПроцедуры

// См. РаботаВМоделиСервисаПереопределяемый.ПриВключенииРазделенияПоОбластямДанных.
Процедура ПриВключенииРазделенияПоОбластямДанных() Экспорт
	
	ТаблицаКалендарей = Справочники.ПроизводственныеКалендари.ПроизводственныеКалендариПоУмолчанию();
	Справочники.ПроизводственныеКалендари.ОбновитьПроизводственныеКалендари(ТаблицаКалендарей);
	ОбновитьИспользованиеНесколькихПроизводственныхКалендарей();
	
	ДанныеПроизводственныхКалендарей = Справочники.ПроизводственныеКалендари.ДанныеПроизводственныхКалендарейПоУмолчанию();
	ПериодыНерабочихДней = Справочники.ПроизводственныеКалендари.ПериодыНерабочихДнейПоУмолчанию();
	ЗаполнитьДанныеПроизводственныхКалендарейПриОбновлении(ДанныеПроизводственныхКалендарей, ПериодыНерабочихДней);
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Обработчики обновления ИБ, используемые в других подсистемах.

// Обновляет данные, зависимые от производственных календарей.
//
Процедура ОбновитьДанныеЗависимыеОтПроизводственныхКалендарей(ПараметрыОбновления) Экспорт
	
	Если Не ПараметрыОбновления.Свойство("ТаблицаИзменений") Тогда
		ПараметрыОбновления.ОбработкаЗавершена = Истина;
		Возврат;
	КонецЕсли;
	
	ТаблицаИзменений = ПараметрыОбновления.ТаблицаИзменений; // ТаблицаЗначений
	ТаблицаИзменений.Свернуть("КодПроизводственногоКалендаря, Год");
	
	ЗаполнитьДанныеЗависимыеОтПроизводственныхКалендарей(ТаблицаИзменений);
	
	ПараметрыОбновления.ОбработкаЗавершена = Истина;
	
КонецПроцедуры

Функция ЕстьИзменяемыеОбъектыЗависимыеОтПроизводственныхКалендарей() Экспорт
	
	ИзменяемыеОбъекты = Новый Массив;
	ЗаполнитьИзменяемыеОбъектыЗависимыеОтПроизводственныхКалендарей(ИзменяемыеОбъекты);
	Возврат ИзменяемыеОбъекты.Количество() > 0;
	
КонецФункции

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

// Получает единственный производственный календарь в ИБ.
//
Функция ЕдинственныйПроизводственныйКалендарь()
	
	ИспользуемыеКалендари = Справочники.ПроизводственныеКалендари.СписокПроизводственныхКалендарей();
	
	Если ИспользуемыеКалендари.Количество() = 1 Тогда
		Возврат ИспользуемыеКалендари[0];
	КонецЕсли;
	
КонецФункции

// Определяет региональный производственный календарь по КПП.
//
Функция РегиональныйПроизводственныйКалендарь(КПП)
	
	Если Метаданные.Обработки.Найти("ЗаполнениеКалендарныхГрафиков") = Неопределено Тогда
		Возврат Неопределено;
	КонецЕсли;	
	
	МодульЗаполнениеКалендарныхГрафиков = ОбщегоНазначения.ОбщийМодуль("Обработки.ЗаполнениеКалендарныхГрафиков");
	Возврат МодульЗаполнениеКалендарныхГрафиков.РегиональныйПроизводственныйКалендарь(КПП);
	
КонецФункции

Процедура ЗагрузитьДанныеПроизводственныхКалендарей(Версия, Адрес, Обработан, ДополнительныеПараметры)
	
	ДанныеКлассификатора = ДанныеФайлаКлассификатора(Адрес);
	
	// Обновляем список производственных календарей.
	ТаблицаКалендарей = ДанныеКлассификатора["ПроизводственныеКалендари"].Данные;
	Справочники.ПроизводственныеКалендари.ОбновитьПроизводственныеКалендари(ТаблицаКалендарей);
	
	// Обновляем данные производственных календарей.
	ДанныеXML = ДанныеКлассификатора["ДанныеПроизводственныхКалендарей"];
	ТаблицаДанных = Справочники.ПроизводственныеКалендари.ДанныеПроизводственныхКалендарейИзXML(ДанныеXML, ТаблицаКалендарей);
	ТаблицаИзменений = Справочники.ПроизводственныеКалендари.ОбновитьДанныеПроизводственныхКалендарей(ТаблицаДанных);
	
	ПериодыXML = ДанныеКлассификатора["ПериодыНерабочихДней"];
	ТаблицаПериодов = Справочники.ПроизводственныеКалендари.ПериодыНерабочихДнейИзXML(ПериодыXML, ТаблицаКалендарей);
	ОбщегоНазначенияКлиентСервер.ДополнитьТаблицу(
		Справочники.ПроизводственныеКалендари.ОбновитьПериодыНерабочихДней(ТаблицаПериодов), ТаблицаИзменений);
	
	ТаблицаИзменений.Свернуть("КодПроизводственногоКалендаря, Год");
	
	КалендарныеГрафикиПереопределяемый.ПриОбновленииПроизводственныхКалендарей(ТаблицаИзменений);
	
	Если Не ОбщегоНазначения.РазделениеВключено() Тогда
		ЗаполнитьДанныеЗависимыеОтПроизводственныхКалендарей(ТаблицаИзменений);
	Иначе
		// Таблицу изменений включаем в состав дополнительных параметров для обновления областей данных.
		ПараметрыОбновления = Новый Структура("ТаблицаИзменений");
		ПараметрыОбновления.ТаблицаИзменений = ТаблицаИзменений;
		ДополнительныеПараметры.Вставить(ИдентификаторКлассификатора(), ПараметрыОбновления);
	КонецЕсли;
	
	Обработан = Истина;
	
КонецПроцедуры

Функция ДанныеФайлаКлассификатора(Адрес)
	
	ДанныеКлассификатора = Новый Структура(
		"ПроизводственныеКалендари,
		|ДанныеПроизводственныхКалендарей,
		|ПериодыНерабочихДней");
	
	ПутьКФайлу = ПолучитьИмяВременногоФайла();
	ДвоичныеДанные = ПолучитьИзВременногоХранилища(Адрес); // ДвоичныеДанные
	ДвоичныеДанные.Записать(ПутьКФайлу);
	
	ЧтениеXML = Новый ЧтениеXML;
	ЧтениеXML.ОткрытьФайл(ПутьКФайлу);
	ЧтениеXML.ПерейтиКСодержимому();
	ПроверитьНачалоЭлемента(ЧтениеXML, "CalendarSuppliedData");
	ЧтениеXML.Прочитать();
	ПроверитьНачалоЭлемента(ЧтениеXML, "Calendars");
	
	ДанныеКлассификатора.ПроизводственныеКалендари = ОбщегоНазначения.ПрочитатьXMLВТаблицу(ЧтениеXML);
	
	ЧтениеXML.Прочитать();
	ПроверитьКонецЭлемента(ЧтениеXML, "Calendars");
	ЧтениеXML.Прочитать();
	ПроверитьНачалоЭлемента(ЧтениеXML, "CalendarData");
	
	ДанныеКлассификатора.ДанныеПроизводственныхКалендарей = ОбщегоНазначения.ПрочитатьXMLВТаблицу(ЧтениеXML);
	
	ЧтениеXML.Прочитать();
	ПроверитьКонецЭлемента(ЧтениеXML, "CalendarData");
	ЧтениеXML.Прочитать();
	ПроверитьНачалоЭлемента(ЧтениеXML, "NonWorkingPeriods");

	ДанныеКлассификатора.ПериодыНерабочихДней = ОбщегоНазначения.ПрочитатьXMLВТаблицу(ЧтениеXML);
	
	ЧтениеXML.Закрыть();
	УдалитьФайлы(ПутьКФайлу);
	
	Возврат ДанныеКлассификатора;
	
КонецФункции

Процедура ПроверитьНачалоЭлемента(Знач ЧтениеXML, Знач Имя)
	
	Если ЧтениеXML.ТипУзла <> ТипУзлаXML.НачалоЭлемента Или ЧтениеXML.Имя <> Имя Тогда
		ИмяСобытия = НСтр("ru = 'Календарные графики.Обработка файла классификатора'", ОбщегоНазначения.КодОсновногоЯзыка());
		ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Неверный формат файла данных. Ожидается начало элемента %1'"), 
			Имя);
		ЗаписьЖурналаРегистрации(ИмяСобытия, УровеньЖурналаРегистрации.Ошибка, , , ТекстСообщения);
		ВызватьИсключение ТекстСообщения;
	КонецЕсли;
	
КонецПроцедуры

Процедура ПроверитьКонецЭлемента(Знач ЧтениеXML, Знач Имя)
	
	Если ЧтениеXML.ТипУзла <> ТипУзлаXML.КонецЭлемента Или ЧтениеXML.Имя <> Имя Тогда
		ИмяСобытия = НСтр("ru = 'Календарные графики.Обработка файла классификатора'", ОбщегоНазначения.КодОсновногоЯзыка());
		ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Неверный формат файла данных. Ожидается конец элемента %1'"), 
			Имя);
		ЗаписьЖурналаРегистрации(ИмяСобытия, УровеньЖурналаРегистрации.Ошибка, , , ТекстСообщения);
		ВызватьИсключение ТекстСообщения;
	КонецЕсли;
	
КонецПроцедуры

Функция ВерсияОбновленияПроизводственныхКалендарей()
	
	Если Метаданные.Обработки.Найти("ЗаполнениеКалендарныхГрафиков") = Неопределено Тогда
		Возврат "1.0.0.1";
	КонецЕсли;	
	
	МодульЗаполнениеКалендарныхГрафиков = ОбщегоНазначения.ОбщийМодуль("Обработки.ЗаполнениеКалендарныхГрафиков");
	Возврат МодульЗаполнениеКалендарныхГрафиков.ВерсияОбновленияПроизводственныхКалендарей();
	
КонецФункции

Функция ВерсияОбновленияДанныхПроизводственныхКалендарей()
	
	Если Метаданные.Обработки.Найти("ЗаполнениеКалендарныхГрафиков") = Неопределено Тогда
		Возврат "1.0.0.1";
	КонецЕсли;
	
	МодульЗаполнениеКалендарныхГрафиков = ОбщегоНазначения.ОбщийМодуль("Обработки.ЗаполнениеКалендарныхГрафиков");
	Возврат МодульЗаполнениеКалендарныхГрафиков.ВерсияОбновленияДанныхПроизводственныхКалендарей();
	
КонецФункции

////////////////////////////////////////////////////////////////////////////////
// Обновление информационной базы.

// Обновляет справочник Производственные календари из одноименного макета.
//
Процедура ОбновитьПроизводственныеКалендари() Экспорт
	
	Если ОбщегоНазначения.ЭтоАвтономноеРабочееМесто() Тогда
		Возврат;
	КонецЕсли;
	
	ВерсияВстроенныхКалендарей = ВерсияКалендарей();
	Если ВерсияВстроенныхКалендарей <= ВерсияЗагруженныхКалендарей() Тогда
		Возврат;
	КонецЕсли;
	
	ТаблицаКалендарей = Справочники.ПроизводственныеКалендари.ПроизводственныеКалендариИзМакета();
	Справочники.ПроизводственныеКалендари.ОбновитьПроизводственныеКалендари(ТаблицаКалендарей);
	ОбновитьИспользованиеНесколькихПроизводственныхКалендарей();
	
	ДанныеПроизводственныхКалендарей = Справочники.ПроизводственныеКалендари.ДанныеПроизводственныхКалендарейИзМакета();
	ПериодыНерабочихДней = Справочники.ПроизводственныеКалендари.ПериодыНерабочихДнейИзМакета();
	ЗаполнитьДанныеПроизводственныхКалендарейПриОбновлении(ДанныеПроизводственныхКалендарей, ПериодыНерабочихДней);
	
	Если ОбщегоНазначения.ПодсистемаСуществует("ИнтернетПоддержкаПользователей.РаботаСКлассификаторами") Тогда
		МодульРаботаСКлассификаторами = ОбщегоНазначения.ОбщийМодуль("РаботаСКлассификаторами");
		МодульРаботаСКлассификаторами.УстановитьВерсиюКлассификатора(ИдентификаторКлассификатора(), ВерсияВстроенныхКалендарей);
	КонецЕсли;
	
КонецПроцедуры

// Обновляет данные производственных календарей из макета.
//  ДанныеПроизводственныхКалендарей.
//
Процедура ОбновитьДанныеПроизводственныхКалендарей() Экспорт
	
	Если ОбщегоНазначения.ЭтоАвтономноеРабочееМесто() Тогда
		Возврат;
	КонецЕсли;
	
	ВерсияВстроенныхКалендарей = ВерсияКалендарей();
	Если ВерсияВстроенныхКалендарей <= ВерсияЗагруженныхКалендарей() Тогда
		Возврат;
	КонецЕсли;
	
	ДанныеПроизводственныхКалендарей = Справочники.ПроизводственныеКалендари.ДанныеПроизводственныхКалендарейИзМакета();
	ПериодыНерабочихДней = Справочники.ПроизводственныеКалендари.ПериодыНерабочихДнейИзМакета();
	ЗаполнитьДанныеПроизводственныхКалендарейПриОбновлении(ДанныеПроизводственныхКалендарей, ПериодыНерабочихДней);
	
	Если ОбщегоНазначения.ПодсистемаСуществует("ИнтернетПоддержкаПользователей.РаботаСКлассификаторами") Тогда
		МодульРаботаСКлассификаторами = ОбщегоНазначения.ОбщийМодуль("РаботаСКлассификаторами");
		МодульРаботаСКлассификаторами.УстановитьВерсиюКлассификатора(ИдентификаторКлассификатора(), ВерсияВстроенныхКалендарей);
	КонецЕсли;
	
КонецПроцедуры

// Обновляет данные зависимых производственных календарей от базовых.
//
Процедура ОбновитьДанныеЗависимыхПроизводственныхКалендарей() Экспорт
	
	Если ОбщегоНазначения.ЭтоАвтономноеРабочееМесто() Тогда
		Возврат;
	КонецЕсли;
	
	Запрос = Новый Запрос;
	Запрос.УстановитьПараметр("Год", 2018);
	Запрос.Текст = 
		"ВЫБРАТЬ
		|	ЗависимыеКалендари.Ссылка КАК Календарь,
		|	ЗависимыеКалендари.БазовыйКалендарь КАК БазовыйКалендарь
		|ПОМЕСТИТЬ ВТЗависимыеКалендари
		|ИЗ
		|	Справочник.ПроизводственныеКалендари КАК ЗависимыеКалендари
		|ГДЕ
		|	ЗависимыеКалендари.БазовыйКалендарь <> ЗНАЧЕНИЕ(Справочник.ПроизводственныеКалендари.ПустаяСсылка)
		|;
		|
		|////////////////////////////////////////////////////////////////////////////////
		|ВЫБРАТЬ РАЗЛИЧНЫЕ
		|	ДанныеКалендарей.ПроизводственныйКалендарь КАК ПроизводственныйКалендарь,
		|	ДанныеКалендарей.Год КАК Год
		|ПОМЕСТИТЬ ВТГодыКалендарей
		|ИЗ
		|	РегистрСведений.ДанныеПроизводственногоКалендаря КАК ДанныеКалендарей
		|ГДЕ
		|	ДанныеКалендарей.Год >= &Год
		|;
		|
		|////////////////////////////////////////////////////////////////////////////////
		|ВЫБРАТЬ РАЗЛИЧНЫЕ
		|	ЗависимыеКалендари.БазовыйКалендарь КАК БазовыйКалендарь,
		|	ЗависимыеКалендари.БазовыйКалендарь.Код КАК КодПроизводственногоКалендаря,
		|	ДанныеБазовыхКалендарей.Год КАК Год
		|ИЗ
		|	ВТЗависимыеКалендари КАК ЗависимыеКалендари
		|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТГодыКалендарей КАК ДанныеБазовыхКалендарей
		|		ПО (ДанныеБазовыхКалендарей.ПроизводственныйКалендарь = ЗависимыеКалендари.БазовыйКалендарь)
		|		ЛЕВОЕ СОЕДИНЕНИЕ ВТГодыКалендарей КАК ДанныеЗависимогоКалендаря
		|		ПО (ДанныеЗависимогоКалендаря.ПроизводственныйКалендарь = ЗависимыеКалендари.Календарь)
		|			И (ДанныеЗависимогоКалендаря.Год = ДанныеБазовыхКалендарей.Год)
		|ГДЕ
		|	ДанныеЗависимогоКалендаря.Год ЕСТЬ NULL";
	
	РезультатЗапроса = Запрос.Выполнить();
	Если РезультатЗапроса.Пустой() Тогда
		Возврат;
	КонецЕсли;
	
	ТаблицаИзменений = РезультатЗапроса.Выгрузить();
	Справочники.ПроизводственныеКалендари.ОбновитьДанныеЗависимыхПроизводственныхКалендарей(ТаблицаИзменений);
	
	Если ОбщегоНазначения.РазделениеВключено() Тогда
		ЗапланироватьОбновлениеДанныхЗависимыхОтПроизводственныхКалендарей(ТаблицаИзменений);
		Возврат;
	КонецЕсли;
	
	ПараметрыОбработчика = ОбновлениеИнформационнойБазыСлужебный.ПараметрыОтложенногоОбработчикаОбновления(
		"КалендарныеГрафики.ОбновитьДанныеЗависимыеОтПроизводственныхКалендарей");
	Если ПараметрыОбработчика <> Неопределено И ПараметрыОбработчика.Свойство("ТаблицаИзменений") Тогда
		ОбщегоНазначенияКлиентСервер.ДополнитьТаблицу(ТаблицаИзменений, ПараметрыОбработчика.ТаблицаИзменений);
	КонецЕсли;
	
	ПараметрыОбработчика = Новый Структура("ТаблицаИзменений");
	ПараметрыОбработчика.ТаблицаИзменений = ТаблицаИзменений;
	ОбновлениеИнформационнойБазыСлужебный.ЗаписатьПараметрыОтложенногоОбработчикаОбновления(
		"КалендарныеГрафики.ОбновитьДанныеЗависимыеОтПроизводственныхКалендарей", ПараметрыОбработчика);
	
КонецПроцедуры

Процедура ЗаполнитьДанныеОбновленияДанныхЗависимыхОтПроизводственныхКалендарей(ПараметрыОбновления) Экспорт
	
КонецПроцедуры

Процедура ЗаполнитьБлокируемыеОбъектыЗависимыеОтПроизводственныхКалендарей(Обработчик)
	
	БлокируемыеОбъекты = Новый Массив;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ГрафикиРаботы") Тогда
		МодульГрафикиРаботы = ОбщегоНазначения.ОбщийМодуль("ГрафикиРаботы");
		МодульГрафикиРаботы.ЗаполнитьБлокируемыеОбъектыЗависимыеОтПроизводственныхКалендарей(БлокируемыеОбъекты);
	КонецЕсли;
	
	КалендарныеГрафикиПереопределяемый.ПриЗаполненииБлокируемыхОбъектовЗависимыхОтПроизводственныхКалендарей(БлокируемыеОбъекты);
	
	Обработчик.БлокируемыеОбъекты = СтрСоединить(БлокируемыеОбъекты, ",");
	
КонецПроцедуры

Процедура ЗаполнитьИзменяемыеОбъектыЗависимыеОтПроизводственныхКалендарей(ИзменяемыеОбъекты)
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ГрафикиРаботы") Тогда
		МодульГрафикиРаботы = ОбщегоНазначения.ОбщийМодуль("ГрафикиРаботы");
		МодульГрафикиРаботы.ЗаполнитьИзменяемыеОбъектыЗависимыеОтПроизводственныхКалендарей(ИзменяемыеОбъекты);
	КонецЕсли;
	
	КалендарныеГрафикиПереопределяемый.ПриЗаполненииИзменяемыхОбъектовЗависимыхОтПроизводственныхКалендарей(ИзменяемыеОбъекты);
	
КонецПроцедуры

// Процедура выполняет обновление данных, зависимых от производственных календарей, 
// по всем областям данных.
//
Процедура ЗапланироватьОбновлениеДанныхЗависимыхОтПроизводственныхКалендарей(Знач УсловияОбновления)
	
	КалендарныеГрафикиСлужебный.ЗапланироватьОбновлениеДанныхЗависимыхОтПроизводственныхКалендарей(УсловияОбновления);
	
КонецПроцедуры

Процедура ЗаполнитьДанныеПроизводственныхКалендарейПриОбновлении(ТаблицаДанных, ТаблицаПериодов)
	
	ТаблицаИзменений = Справочники.ПроизводственныеКалендари.ОбновитьДанныеПроизводственныхКалендарей(ТаблицаДанных);

	ОбщегоНазначенияКлиентСервер.ДополнитьТаблицу(
		Справочники.ПроизводственныеКалендари.ОбновитьПериодыНерабочихДней(ТаблицаПериодов), ТаблицаИзменений);
	
	Если ОбщегоНазначения.РазделениеВключено() Тогда
		ЗапланироватьОбновлениеДанныхЗависимыхОтПроизводственныхКалендарей(ТаблицаИзменений);
		Возврат;
	КонецЕсли;

	ПараметрыОбработчика = ОбновлениеИнформационнойБазыСлужебный.ПараметрыОтложенногоОбработчикаОбновления(
		"КалендарныеГрафики.ОбновитьДанныеЗависимыеОтПроизводственныхКалендарей");
	Если ПараметрыОбработчика <> Неопределено И ПараметрыОбработчика.Свойство("ТаблицаИзменений") Тогда
		ОбщегоНазначенияКлиентСервер.ДополнитьТаблицу(ТаблицаИзменений, ПараметрыОбработчика.ТаблицаИзменений);
	КонецЕсли;
	
	ПараметрыОбработчика = Новый Структура("ТаблицаИзменений");
	ПараметрыОбработчика.ТаблицаИзменений = ТаблицаИзменений;
	ОбновлениеИнформационнойБазыСлужебный.ЗаписатьПараметрыОтложенногоОбработчикаОбновления(
		"КалендарныеГрафики.ОбновитьДанныеЗависимыеОтПроизводственныхКалендарей", ПараметрыОбработчика);
	
КонецПроцедуры

// Устанавливает значение константы, определяющей использование нескольких производственных календарей.
//
Процедура ОбновитьИспользованиеНесколькихПроизводственныхКалендарей() Экспорт
	
	Если ОбщегоНазначения.ЭтоАвтономноеРабочееМесто() Тогда
		Возврат;
	КонецЕсли;
	
	ИспользоватьНесколькоКалендарей = Справочники.ПроизводственныеКалендари.СписокПроизводственныхКалендарей().Количество() <> 1;
	Если ИспользоватьНесколькоКалендарей <> ПолучитьФункциональнуюОпцию("ИспользоватьНесколькоПроизводственныхКалендарей") Тогда
		Константы.ИспользоватьНесколькоПроизводственныхКалендарей.Установить(ИспользоватьНесколькоКалендарей);
	КонецЕсли;
	
КонецПроцедуры

Процедура ДобавитьОбработчикДанныхЗависимыхОтПроизводственныхКалендарей(Обработчики)
	
	Если ОбщегоНазначения.РазделениеВключено() Тогда
		// В режиме сервиса запускается с помощью альтернативной механики.
		Возврат;
	КонецЕсли;
	
	ИзменяемыеОбъекты = Новый Массив;
	ЗаполнитьИзменяемыеОбъектыЗависимыеОтПроизводственныхКалендарей(ИзменяемыеОбъекты);
	Если ИзменяемыеОбъекты.Количество() = 0 Тогда
		// Не подключается никаких зависимых объектов.
		Возврат;
	КонецЕсли;
	
	Обработчик = Обработчики.Добавить();
	Обработчик.Версия = ВерсияОбновленияДанныхПроизводственныхКалендарей();
	Обработчик.Процедура = "КалендарныеГрафики.ОбновитьДанныеЗависимыеОтПроизводственныхКалендарей";
	Обработчик.ПроцедураЗаполненияДанныхОбновления = "КалендарныеГрафики.ЗаполнитьДанныеОбновленияДанныхЗависимыхОтПроизводственныхКалендарей";
	Обработчик.РежимВыполнения = "Отложенно";
	Обработчик.ЗапускатьИВПодчиненномУзлеРИБСФильтрами = Истина;
	Обработчик.ЧитаемыеОбъекты = "РегистрСведений.ДанныеПроизводственногоКалендаря";
	Обработчик.ПроцедураПроверки = "ОбновлениеИнформационнойБазы.ДанныеОбновленыНаНовуюВерсиюПрограммы";
	Обработчик.Идентификатор = Новый УникальныйИдентификатор("b1082291-b482-418f-82ab-3c96e93072cc");
	Обработчик.Комментарий = НСтр("ru = 'Обновление графиков работы и др. данных, зависимых от производственных календарей.'");
	Обработчик.ИзменяемыеОбъекты = СтрСоединить(ИзменяемыеОбъекты, ",");
	ЗаполнитьБлокируемыеОбъектыЗависимыеОтПроизводственныхКалендарей(Обработчик);
	Обработчик.ПриоритетыВыполнения = ОбновлениеИнформационнойБазы.ПриоритетыВыполненияОбработчика();
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ГрафикиРаботы") Тогда
		МодульГрафикиРаботы = ОбщегоНазначения.ОбщийМодуль("ГрафикиРаботы");
		Приоритет = Обработчик.ПриоритетыВыполнения.Добавить();
		Приоритет.Процедура = МодульГрафикиРаботы.ИмяПроцедурыОбновленияГрафиковРаботы();
		Приоритет.Порядок = "До";
		Приоритет = Обработчик.ПриоритетыВыполнения.Добавить();
		Приоритет.Процедура = МодульГрафикиРаботы.ИмяПроцедурыУстановкиПризнакаУчитыватьНерабочиеДни();
		Приоритет.Порядок = "После";
	КонецЕсли;
	
КонецПроцедуры

Процедура УдалитьПериодыНеСоответствующиеОтбору(Периоды, ПериодОтбор)
	
	Индекс = 0;
	Пока Индекс < Периоды.Количество() Цикл
		ОписаниеПериода = Периоды[Индекс];
		Если ПериодОтбор.ДатаНачала > ОписаниеПериода.Период.ДатаОкончания 
			Или (ЗначениеЗаполнено(ПериодОтбор.ДатаОкончания) И ПериодОтбор.ДатаОкончания < ОписаниеПериода.Период.ДатаНачала) Тогда
			Периоды.Удалить(Индекс);
		Иначе
			Индекс = Индекс + 1;
		КонецЕсли; 
	КонецЦикла;
	
КонецПроцедуры

Функция НерабочиеДатыПоНерабочимПериодам(НерабочиеПериоды, ПроизводственныйКалендарь)

	НерабочиеДаты = Новый Массив;

	Если ТипЗнч(НерабочиеПериоды) = Тип("Массив") Тогда
		Если НерабочиеПериоды.Количество() = 0 Тогда
			Возврат НерабочиеДаты;
		КонецЕсли;
		Если ТипЗнч(НерабочиеПериоды[0]) = Тип("Число") Тогда
			ОписанияПериодов = ПериодыНерабочихДней(ПроизводственныйКалендарь, Новый СтандартныйПериод());
			Индекс = 0;
			Пока Индекс < ОписанияПериодов.Количество() Цикл
				Если НерабочиеПериоды.Найти(ОписанияПериодов[Индекс].Номер) = Неопределено Тогда
					ОписанияПериодов.Удалить(Индекс);
				Иначе
					Индекс = Индекс + 1;
				КонецЕсли; 
			КонецЦикла;
		ИначеЕсли ТипЗнч(НерабочиеПериоды[0]) = Тип("Структура") Тогда
			ОписанияПериодов = НерабочиеПериоды;
		Иначе
			ОбщегоНазначенияКлиентСервер.Проверить(Ложь,
				СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Недопустимый тип значения элемента в параметре %1:
					           |%2'"), "НерабочиеПериоды", ТипЗнч(НерабочиеПериоды[0])),
				"КалендарныеГрафики.БлижайшиеРабочиеДаты");
		КонецЕсли;
	КонецЕсли;

	Если НерабочиеПериоды = Неопределено Тогда
		ОписанияПериодов = ПериодыНерабочихДней(ПроизводственныйКалендарь, Новый СтандартныйПериод());
	КонецЕсли;
	
	Для Каждого Период Из ОписанияПериодов Цикл
		ОбщегоНазначенияКлиентСервер.ДополнитьМассив(НерабочиеДаты, Период.Даты);
	КонецЦикла;
	
	Возврат НерабочиеДаты;
	
КонецФункции

Процедура СброситьВерсиюКлассификатора() Экспорт
	
	Если ВерсияЗагруженныхКалендарей() = 0 Тогда
		Возврат;
	КонецЕсли;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("ИнтернетПоддержкаПользователей.РаботаСКлассификаторами") Тогда
		МодульРаботаСКлассификаторами = ОбщегоНазначения.ОбщийМодуль("РаботаСКлассификаторами");
		МодульРаботаСКлассификаторами.УстановитьВерсиюКлассификатора(ИдентификаторКлассификатора(), 1);
	КонецЕсли;
	
КонецПроцедуры

Процедура ИсправитьДанныеЗависимыхКалендарей() Экспорт
	
	Если ОбщегоНазначения.ЭтоАвтономноеРабочееМесто() Тогда
		Возврат;
	КонецЕсли;
	
	Запрос = Новый Запрос();
	Запрос.УстановитьПараметр("ГодНачалаОбновленияЗависимых", 2018);
	Запрос.Текст = 
		"ВЫБРАТЬ РАЗЛИЧНЫЕ
		|	ЗависимыеКалендари.Ссылка.Код КАК КодКалендаря
		|ИЗ
		|	РегистрСведений.ДанныеПроизводственногоКалендаря КАК ДанныеБазовогоКалендаря
		|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ПроизводственныеКалендари КАК ЗависимыеКалендари
		|		ПО (ЗависимыеКалендари.БазовыйКалендарь = ДанныеБазовогоКалендаря.ПроизводственныйКалендарь)
		|			И (ДанныеБазовогоКалендаря.ПроизводственныйКалендарь.БазовыйКалендарь = ЗНАЧЕНИЕ(Справочник.ПроизводственныеКалендари.ПустаяСсылка))
		|			И (ДанныеБазовогоКалендаря.Год >= &ГодНачалаОбновленияЗависимых)
		|			И (НЕ ИСТИНА В
		|					(ВЫБРАТЬ ПЕРВЫЕ 1
		|						ИСТИНА
		|					ИЗ
		|						РегистрСведений.ДанныеПроизводственногоКалендаря КАК Данные
		|					ГДЕ
		|						Данные.ПроизводственныйКалендарь = ЗависимыеКалендари.Ссылка
		|						И Данные.Год = ДанныеБазовогоКалендаря.Год))";

	КодыКалендарей = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("КодКалендаря");
	Если КодыКалендарей.Количество() = 0 Тогда
		Возврат;
	КонецЕсли;

	ДанныеПроизводственныхКалендарей = Справочники.ПроизводственныеКалендари.ДанныеПроизводственныхКалендарейПоУмолчанию(КодыКалендарей);
	ПериодыНерабочихДней = Справочники.ПроизводственныеКалендари.ПериодыНерабочихДнейПоУмолчанию();
	ЗаполнитьДанныеПроизводственныхКалендарейПриОбновлении(ДанныеПроизводственныхКалендарей, ПериодыНерабочихДней);

КонецПроцедуры

#КонецОбласти
